#pragma once

#include "MeshDef.h"

#include <stack>
#include <map>

namespace LSCM
{
	/**
	 * @file Feature.h
	 * @author xingyifan
	 * @date 2023-08-14 17:28
	 *
	 * @description: 特征类，保存边的特征值
	 */

	class Feature
	{
	private:
		Mesh::EdgeHandle m_edge; // 记录边
		float m_value;			 // 特征值

	public:
		Feature() : m_edge(), m_value(0) {}
		Feature(const Mesh::EdgeHandle& edge, float value) : m_edge(edge), m_value(value) {}

		float value() const { return m_value; }
		const Mesh::EdgeHandle& edge() const { return m_edge; }
		bool operator==(const Feature& other) const { return edge() == other.edge(); }

		// 特征比较器
		static bool greater(const Feature& a, const Feature& b) { return a.value() > b.value(); }
	};

	/**
	 * @file Feature.h
	 * @author xingyifan
	 * @date 2023-08-14 17:38
	 *
	 * @description: 保存特征半边的集合
	 */

	class FeatureSet
	{
	private:
		static Mesh::Scalar s_count;

	private:
		Mesh::Scalar m_id;			// 标记特征集
		HalfedgeList m_halfedges;	// 记录特征半边
		Mesh::Scalar m_totalValue;	// 记录集合中特征值的和

	public:
		FeatureSet() : m_id(s_count++), m_totalValue(0) {}

		Mesh::Scalar id() const { return m_id; }
		size_t size() const { return m_halfedges.size(); }
		bool empty() const { return m_halfedges.empty(); }
		HalfedgeList& halfedges() { return m_halfedges; }
		const HalfedgeList& halfedges() const { return m_halfedges; }

		void clear();
		bool add(const Mesh::HalfedgeHandle& halfedge, Mesh::Scalar value); // 加入新的特征半边
		bool contains(const Mesh::HalfedgeHandle& halfedge) const;			// 检查是否包含该特征半边
	};

	/**
	 * @file Feature.h
	 * @author xingyifan
	 * @date 2023-08-14 18:00
	 *
	 * @description: 特征度量虚类
	 */

	class FeatureMetric
	{
	public:
		virtual float eval(const Mesh* mesh, const Mesh::EdgeHandle& edge) = 0;
		virtual bool operator>(float value) = 0;

		virtual float threshold() const = 0;
	};

	// Second Order Differences (SOD) - Angle between the normals
	class SODFeatureMetric : public FeatureMetric
	{
	private:
		float m_threshold; // 特征阈值

	public:
		SODFeatureMetric(float threshold) : m_threshold(threshold) {}

		virtual float eval(const Mesh* mesh, const Mesh::EdgeHandle& edge)
		{
			// 利用二面角估计 SOD 二阶差分（法向之间的夹角），弧度转换为角度
			return OpenMesh::rad_to_deg(std::fabs(mesh->calc_dihedral_angle_fast(edge)));
		}

		virtual bool operator>(float value) { return m_threshold > value; }
		virtual float threshold() const { return m_threshold; }
	};

} // namespace MeshOp